# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
import frappe.utils
from frappe.utils import get_url_to_form
from frappe.model import log_types
from frappe import _
from itertools import groupby

@frappe.whitelist()
def update_follow(doctype, doc_name, following):
	if following:
		return follow_document(doctype, doc_name, frappe.session.user)
	else:
		return unfollow_document(doctype, doc_name, frappe.session.user)


@frappe.whitelist()
def follow_document(doctype, doc_name, user):
	'''
		param:
		Doctype name
		doc name
		user email

		condition:
		avoided for some doctype
		follow only if track changes are set to 1
	'''
	if (doctype in ("Communication", "ToDo", "Email Unsubscribe", "File", "Comment", "Email Account", "Email Domain")
		or doctype in log_types):
		return

	if ((not frappe.get_meta(doctype).track_changes)
		or user == "Administrator"):
		return

	if not frappe.db.get_value("User", user, "document_follow_notify", ignore=True, cache=True):
		return

	if not is_document_followed(doctype, doc_name, user):
		doc = frappe.new_doc("Document Follow")
		doc.update({
			"ref_doctype": doctype,
			"ref_docname": doc_name,
			"user": user
		})
		doc.save()
		return doc

@frappe.whitelist()
def unfollow_document(doctype, doc_name, user):
	doc = frappe.get_all(
		"Document Follow",
		filters={
			"ref_doctype": doctype,
			"ref_docname": doc_name,
			"user": user
		},
		fields=["name"],
		limit=1
	)
	if doc:
		frappe.delete_doc("Document Follow", doc[0].name)
		return 1
	return 0

def get_message(doc_name, doctype, frequency, user):
	activity_list = get_version(doctype, doc_name, frequency, user) + get_comments(doctype, doc_name, frequency, user)
	return sorted(activity_list, key=lambda k: k["time"], reverse=True)

def send_email_alert(receiver, docinfo, timeline):
	if receiver:
		frappe.sendmail(
			subject=_("Document Follow Notification"),
			recipients=[receiver],
			template="document_follow",
			args={
				"docinfo": docinfo,
				"timeline": timeline,
			}
		)

def send_document_follow_mails(frequency):
	'''
		param:
		frequency for sanding mails

		task:
		set receiver according to frequency
		group document list according to user
		get changes, activity, comments on doctype
		call method to send mail
	'''

	users = frappe.get_list("Document Follow",
		fields=["*"])

	sorted_users = sorted(users, key=lambda k: k['user'])

	grouped_by_user = {}
	for k, v in groupby(sorted_users, key=lambda k: k['user']):
		grouped_by_user[k] = list(v)

	for user in grouped_by_user:
		user_frequency = frappe.db.get_value("User", user, "document_follow_frequency")
		message = []
		valid_document_follows = []
		if user_frequency == frequency:
			for d in grouped_by_user[user]:
				content = get_message(d.ref_docname, d.ref_doctype, frequency, user)
				if content:
					message = message + content
					valid_document_follows.append({
						"reference_docname": d.ref_docname,
						"reference_doctype": d.ref_doctype,
						"reference_url": get_url_to_form(d.ref_doctype, d.ref_docname)
					})

			if message and frappe.db.get_value("User", user, "document_follow_notify", ignore=True):
				send_email_alert(user, valid_document_follows, message)


def get_version(doctype, doc_name, frequency, user):
	timeline = []
	filters = get_filters("docname", doc_name, frequency, user)
	version = frappe.get_all("Version",
		filters=filters,
		fields=["ref_doctype", "data", "modified", "modified", "modified_by"]
	)
	if version:
		for v in version:
			change = frappe.parse_json(v.data)
			time = frappe.utils.format_datetime(v.modified, "hh:mm a")
			timeline_items = []
			if change.changed:
				timeline_items = get_field_changed(change.changed, time, doctype, doc_name, v)
			if change.row_changed:
				timeline_items = get_row_changed(change.row_changed, time, doctype, doc_name, v)
			if change.added:
				timeline_items = get_added_row(change.added, time, doctype, doc_name, v)

			timeline = timeline + timeline_items

	return timeline

def get_comments(doctype, doc_name, frequency, user):
	from html2text import html2text

	timeline = []
	filters = get_filters("reference_name", doc_name, frequency, user)
	comments = frappe.get_all("Comment",
		filters=filters,
		fields=["content", "modified", "modified_by", "comment_type"]
	)
	for comment in comments:
		if comment.comment_type == "Like":
			by = ''' By : <b>{0}<b>'''.format(comment.modified_by)
		elif comment.comment_type == "Comment":
			by = '''Commented by : <b>{0}<b>'''.format(comment.modified_by)
		else:
			by = ''

		time = frappe.utils.format_datetime(comment.modified, "hh:mm a")
		timeline.append({
			"time": comment.modified,
			"data": {
				"time": time,
				"comment": html2text(str(comment.content)),
				"by": by
			},
			"doctype": doctype,
			"doc_name": doc_name,
			"type": "comment"
		})
	return timeline

def is_document_followed(doctype, doc_name, user):
	return frappe.db.exists(
		"Document Follow",
		{
			"ref_doctype": doctype,
			"ref_docname": doc_name,
			"user": user
		}
	)

@frappe.whitelist()
def get_follow_users(doctype, doc_name):
	return frappe.get_all(
		"Document Follow",
		filters={
			"ref_doctype": doctype,
			"ref_docname":doc_name
		},
		fields=["user"]
	)

def get_row_changed(row_changed, time, doctype, doc_name, v):
	from html2text import html2text

	items = []
	for d in row_changed:
		d[2] = d[2] if d[2] else ' '
		d[0] = d[0] if d[0] else ' '
		d[3][0][1] = d[3][0][1] if d[3][0][1] else ' '
		items.append({
			"time": v.modified,
			"data": {
					"time": time,
					"table_field": d[0],
					"row": str(d[1]),
					"field": d[3][0][0],
					"from": html2text(str(d[3][0][1])),
					"to": html2text(str(d[3][0][2]))
				},
			"doctype": doctype,
			"doc_name": doc_name,
			"type": "row changed",
			"by": v.modified_by
		})
	return items

def get_added_row(added, time, doctype, doc_name, v):
	items = []
	for d in added:
		items.append({
			"time": v.modified,
			"data": {
					"to": d[0],
					"time": time
				},
			"doctype": doctype,
			"doc_name": doc_name,
			"type": "row added",
			"by": v.modified_by
		})
	return items

def get_field_changed(changed, time, doctype, doc_name, v):
	from html2text import html2text

	items = []
	for d in changed:
		d[1] = d[1] if d[1] else ' '
		d[2] = d[2] if d[2] else ' '
		d[0] = d[0] if d[0] else ' '
		items.append({
			"time": v.modified,
			"data": {
					"time": time,
					"field": d[0],
					"from": html2text(str(d[1])),
					"to": html2text(str(d[2]))
				},
			"doctype": doctype,
			"doc_name": doc_name,
			"type": "field changed",
			"by": v.modified_by
		})
	return items

def send_hourly_updates():
	send_document_follow_mails("Hourly")

def send_daily_updates():
	send_document_follow_mails("Daily")

def send_weekly_updates():
	send_document_follow_mails("Weekly")

def get_filters(search_by, name, frequency, user):
	filters = []

	if frequency == "Weekly":
		filters = [
			[search_by, "=", name],
			["modified", ">", frappe.utils.add_days(frappe.utils.nowdate(),-7)],
			["modified", "<", frappe.utils.nowdate()],
			["modified_by", "!=", user]
		]
	elif frequency == "Daily":
		filters = [
			[search_by, "=", name],
			["modified", ">", frappe.utils.add_days(frappe.utils.nowdate(),-1)],
			["modified", "<", frappe.utils.nowdate()],
			["modified_by", "!=", user]
		]
	elif frequency == "Hourly":
		filters = [
			[search_by, "=", name],
			["modified", ">", frappe.utils.add_to_date(frappe.utils.now_datetime(), hours=-1)],
			["modified", "<", frappe.utils.now_datetime()],
			["modified_by", "!=", user]
		]

	return filters
